/*
 * @Author       : wang chao
 * @Date         : 2022-10-27 18:36:06
 * @LastEditors  : wang chao
 * @LastEditTime : 2023-08-08 15:52:13
 * @FilePath     : u_dac.c
 * @Description  : mcp4726 & st dac driver
 * Copyright 2022 BingShan, All Rights Reserved.
 */
#include <rtdevice.h>
#include <rtthread.h>
#include "board.h"
#include "u_data.h"

/**
 * what is mcp4726 ?
 * MCP4726 is a single channel, 12-bit,
 * voltage output Digital-to-Analog Converter with integrated EEPROM and an I2C Compatible Serial
 * Interface.
 */
#define MCP4726_I2C_BUS_NAME    "i2c1"
#define MCP4726_ADDR            0x60
#define MCP4726_RESOLUTION_MASK 0x0FFF
#define MCP4726_REFENCE_VOLTAGE 5000.0F

DAC_Param DAC_Cali_Param;

static rt_int16_t st_dac1_calcul_base = 0;
static rt_int16_t st_dac2_calcul_base = 0;
static rt_int16_t mcp_dac1_calcul_base = 0;
static rt_int16_t mcp_dac2_calcul_base = 0;

static struct rt_i2c_bus_device* mcp_i2c_bus = RT_NULL;
static rt_bool_t initialized = RT_FALSE;

static rt_err_t mcp4726_write_reg(struct rt_i2c_bus_device* bus, rt_uint8_t* data)
{
    rt_uint8_t buf[3];
    struct rt_i2c_msg msgs;
    rt_uint32_t buf_size = 1;

    buf[0] = data[0];
    if (data != RT_NULL)
    {
        buf[1] = data[1];
        buf[2] = data[2];
        buf_size = 3;
    }

    msgs.addr = MCP4726_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = buf_size;

    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return RT_ERROR;
    }
}

extern void mcp_select_chip(rt_uint8_t cx);
static void select_chx(rt_uint8_t chx)
{
    mcp_select_chip(chx);
}

rt_err_t mcp4726_init(void)
{
    mcp_i2c_bus = (struct rt_i2c_bus_device*)rt_device_find(MCP4726_I2C_BUS_NAME);
    if (mcp_i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", MCP4726_I2C_BUS_NAME);
        return RT_ERROR;
    }
    return RT_EOK;
}

rt_err_t mcp4726_dac_set(rt_uint8_t chx, rt_uint16_t val)
{
    rt_uint8_t pWriteBuf[3];
    rt_uint16_t temp = 0;
    // select channel ch1 or ch2
    select_chx(chx);

    temp = (rt_uint16_t)((val)*MCP4726_RESOLUTION_MASK / MCP4726_REFENCE_VOLTAGE);
    temp &= 0x0FFF;

    // rt_kprintf("mc dac:ch1/ch2 set value is: %d\n", val);
    pWriteBuf[0] = 0x40;
    pWriteBuf[1] = (rt_uint8_t)((temp & 0xFF0) >> 4);
    pWriteBuf[2] = (rt_uint8_t)((temp & 0xF) << 4);
    mcp4726_write_reg(mcp_i2c_bus, pWriteBuf);
    return RT_EOK;
}

#if 0
void mcp_dac_set_test(int argc, char** argv)
{
    float       f_value     = 0.0;
    rt_uint16_t value       = 0;
    int16_t     mcp_dac_set = 0;
    if (mcp4726_init() == RT_EOK)
    {
        rt_kprintf("mcp dac init success\n");
    }

    mcp_dac_set = 400;
    // MCP DAC Set
    f_value = (float)(DAC_Cali_Param.mcp_dac1_hv / 1000.0);
    value = (uint16_t)(f_value * ((float)(mcp_dac_set)) + (float)(DAC_Cali_Param.mcp_dac1_lv));
    mcp4726_dac_set(1, value);
}
MSH_CMD_EXPORT(mcp_dac_set_test, mcp dac set test)
#endif

#define DAC_DEV_NAME  "dac1" /*DAC1 设备名称*/
#define DAC_DEV_CH1   1 /*DAC1 通道1*/
#define DAC_DEV_CH2   2 /*DAC1 通道2*/
#define REFER_VOLTAGE 250 /*参考电压 2.5V,数据精度乘以100保留2位小数*/
#define CONVERT_BITS  (1 << 12) /*转换位数为12位*/
static rt_dac_device_t dac_dev;

rt_err_t st_dac_device_init(void)
{
    rt_err_t ret = RT_EOK;

    /*查找设备*/
    dac_dev = (rt_dac_device_t)rt_device_find(DAC_DEV_NAME);
    if (dac_dev == RT_NULL)
    {
        rt_kprintf("dac sample run failed! can't find %s device!\n", DAC_DEV_NAME);
        return RT_ERROR;
    }

    /*使能设备通道1*/
    ret = rt_dac_enable(dac_dev, DAC_DEV_CH1);
    if (ret != RT_EOK)
    {
        return ret;
    }
    /*使能设备通道2*/
    ret = rt_dac_enable(dac_dev, DAC_DEV_CH2);
    if (ret != RT_EOK)
    {
        return ret;
    }

    return RT_EOK;
}

rt_err_t st_dac_set(rt_uint8_t chx, rt_uint16_t val)
{
    rt_err_t ret = RT_EOK;
    if (dac_dev != RT_NULL)
    {
        ret = rt_dac_write(dac_dev, chx, val);
        return ret;
    }
    return RT_ERROR;
}

void system_dac_init(void)
{
    rt_thread_mdelay(100);
    rt_kprintf("system dac init.\n");
    // 读取校准参数
    if (get_dac_calibrate_parameters() == RT_TRUE)
    {
        st_dac1_calcul_base = DAC_Cali_Param.st_dac1_hv - DAC_Cali_Param.st_dac1_lv;
        st_dac2_calcul_base = DAC_Cali_Param.st_dac2_hv - DAC_Cali_Param.st_dac1_lv;
        mcp_dac1_calcul_base = DAC_Cali_Param.mcp_dac1_hv - DAC_Cali_Param.mcp_dac1_lv;
        mcp_dac2_calcul_base = DAC_Cali_Param.mcp_dac2_hv - DAC_Cali_Param.mcp_dac2_lv;
        rt_kprintf("get dac calibrate parameters success.\n");
    }
    rt_thread_mdelay(20);
    mcp4726_init();
    rt_thread_mdelay(20);
    st_dac_device_init();
    rt_thread_mdelay(20);
    // st dac1 & dac2 set
    st_dac_set(DAC_DEV_CH1, DAC_Cali_Param.st_dac1_lv);
    st_dac_set(DAC_DEV_CH2, DAC_Cali_Param.st_dac2_lv);
    // st mcp set
    mcp4726_dac_set(DAC_DEV_CH1, DAC_Cali_Param.mcp_dac1_lv);
    mcp4726_dac_set(DAC_DEV_CH2, DAC_Cali_Param.mcp_dac2_lv);
}

void system_dac_stop_output(void)
{
    // st dac1 & dac2 set
    st_dac_set(DAC_DEV_CH1, DAC_Cali_Param.st_dac1_lv);
    st_dac_set(DAC_DEV_CH2, DAC_Cali_Param.st_dac2_lv);
    // st mcp set
    mcp4726_dac_set(DAC_DEV_CH1, DAC_Cali_Param.mcp_dac1_lv);
    mcp4726_dac_set(DAC_DEV_CH2, DAC_Cali_Param.mcp_dac2_lv);
}

void system_dac_max_output(void)
{
    // st dac1 & dac2 set
    st_dac_set(DAC_DEV_CH1, DAC_Cali_Param.st_dac1_hv);
    st_dac_set(DAC_DEV_CH2, DAC_Cali_Param.st_dac2_hv);
    // st mcp set
    mcp4726_dac_set(DAC_DEV_CH1, DAC_Cali_Param.mcp_dac1_hv);
    mcp4726_dac_set(DAC_DEV_CH2, DAC_Cali_Param.mcp_dac2_hv);
}

rt_uint16_t manual_set_params[3] = {0};

extern rt_uint16_t P_PUMP_SET_HZ;
extern rt_uint16_t N_PUMP_SET_HZ;

void system_dac_set_manual_clean(void)
{
    manual_set_params[0] = 0;
    manual_set_params[1] = 0;
    manual_set_params[2] = 0;
    //
    P_PUMP_SET_HZ = 200;
    N_PUMP_SET_HZ = 200;
}

void system_hz_output_by_manual(rt_uint8_t chx, rt_uint16_t hz)
{
    float f_value = 0.0;

    hz = (hz > 500) ? 500 : hz;
    hz = (hz <= 0) ? 0 : hz;

    f_value = (float)(hz / 500.0);

    manual_set_params[chx - 1] = hz;

    if (chx == 1)
        P_PUMP_SET_HZ = hz;

    if (chx == 2)
        N_PUMP_SET_HZ = hz;

    switch (chx)
    {
        case 1:
            st_dac_set(DAC_DEV_CH1, (uint16_t)(f_value * (st_dac1_calcul_base) + DAC_Cali_Param.st_dac1_lv));
            break;
        case 2:
            st_dac_set(DAC_DEV_CH2, (uint16_t)(f_value * (st_dac2_calcul_base) + DAC_Cali_Param.st_dac2_lv));
            break;
        default:
            break;
    }
}

void system_dac_output_by_manual(rt_uint8_t chx, rt_uint16_t percent)
{
    float f_value = 0.0;

    percent = (percent > 1000) ? 1000 : percent;
    percent = (percent <= 0) ? 0 : percent;

    rt_kprintf("dac set by manual percent:%d\n", percent);

    f_value = (float)(percent / 1000.0);

    manual_set_params[chx - 1] = percent;
    switch (chx)
    {
        case 3:
            mcp4726_dac_set(DAC_DEV_CH1, (uint16_t)(f_value * (mcp_dac1_calcul_base) + DAC_Cali_Param.mcp_dac1_lv));
            break;
        default:
            break;
    }
}
